#include <fstream>
#include <algorithm>
#include <ctype.h>
#include "tcp_server.hpp"

void Ping(thread_data tmp)
{
    tmp._inet.print_client_info("ping");

    char buffer[1024] = {0};
    int n = read(tmp._sockfd, buffer, sizeof(buffer) - 1);
    if (n > 0)
    {
        buffer[n] = 0;
        lg.Log_infom(Debug, "server recieve info:%s", buffer);
    }
    else if (n == 0) // 读到文件末尾
    {
        lg.Log_infom(Info, "数据已经全部读取完毕...");
    }
    else
    {
        lg.Log_infom(Error, "数据读取失败");
    }

    write(tmp._sockfd, buffer, strlen(buffer)); // sizeof此时大小还是1024
    cout << "send info: " << buffer << endl;
}
class dict
{
public:
    map<string, string> _dicts;
    dict()
    {
        // 直接将txt文本文件中的单词全部录入到dicts中
        std::ifstream file("./test.txt"); // 打开文件
        vector<string> lines;
        string line;
        if (file.is_open())// 检查文件是否成功打开
        {
            
            while (std::getline(file, line)) // 按行读取文件内容
            {
                lines.push_back(line);
            }
            file.close(); // 关闭文件
        }
        else
        {
            std::cerr << "无法打开文件" << std::endl;
        }

        // 将lines中的数据按照key-val的形式填入
        for (auto &s : lines)
        {
            string tmp = s;
            int i = s.find(' ');
            _dicts[tmp.substr(0, i)] = tmp.substr(i + 1);
        }
    }
    const string operator[](const string &tmp)
    {
        if (_dicts.find(tmp) == _dicts.end())
            return "暂时还未录入该数据到词典中";
        return _dicts[tmp];
    }
    ~dict()
    {
    }
};

dict dictionary;//放到外面就不用每次都重行初始化
void Translate(thread_data tmp)
{    
    tmp._inet.print_client_info("translate");

    // 读取任务
    char buffer[1024] = {0};
    int n = read(tmp._sockfd, buffer, sizeof(buffer) - 1);
    string s;
    if (n > 0)
    {
        buffer[n] = 0;
        s = buffer;
    }
    string chines = dictionary[s];

    // 返回任务结果
    write(tmp._sockfd, chines.c_str(), chines.size()); // sizeof此时大小还是1024
    cout << "send info: " << chines << endl;
}

void Transform(thread_data tmp)
{
    tmp._inet.print_client_info("transform");

    // 读取任务
    char buffer[1024] = {0};
    int n = read(tmp._sockfd, buffer, sizeof(buffer) - 1);
    string s;
    if (n > 0)
    {
        buffer[n] = 0;
        s = buffer;
    }

    std::transform(s.begin(), s.end(), s.begin(), [](char c) -> char
                   { return toupper(c); });
    // 返回任务结果
    write(tmp._sockfd, s.c_str(), s.size()); // sizeof此时大小还是1024
    cout << "send info: " << s << endl;
}
void default_func(thread_data tmp)
{
    tmp._inet.print_client_info("default");

    // 读取任务不处理
    char buffer[1024] = {0};
    read(tmp._sockfd, buffer, sizeof(buffer) - 1);

    // 返回任务结果
    string s = "目前没有该类型任务，请重新输入正确的任务类型,例如1.ping 2.translate 3.transform";
    write(tmp._sockfd, s.c_str(), s.size());
    cout << "send info: " << s << endl;
}

void daemon(int is_change)
{
    // 一个会话内部可以有多个进程组，但默认任何时刻只有一个进程组在前台

    // 1.守护进程自己是一个独立的会话，不隶属于任何一个bash会话。

    pid_t fi = fork(); // 当父进程退出时，进程组的组长不会改变，仍然是原来的组长进程

    // 2.让自己不要成为组长，关闭父进程，守护进程也就是孤儿进程,其父进程是系统（pid=1）
    if (fi > 0)
        exit(0);

    // 3. // 返回新的会话，即pid=pgid=sid（条件是，调用进程不能是进程组的组长）
    pid_t si = setsid();
    if (si == -1)
    {
        cout << "调用该函数失败失败,不能是组长调用该进程" << endl;
        exit(-1);
    }

    // 4.是否将当前工作目录更改为根目录
    if (is_change)
        chdir("/");

    // 5.守护进程不需要进行输入输出,将输入输出到/dev/null下
    int fd = open("/dev/null", O_RDWR);
    if (fd > 0)
    {
        // 重定向
        dup2(fd, 0);
        dup2(fd, 1);
        dup2(fd, 2);
        close(fd);
    }
}
int main(int argc, char *argv[])
{
    daemon(0);

    if (argc != 2)
    {
        cout << "格式错误,正确格式:" << argv[0] << " port" << endl;
    }
    uint16_t port = atoi(argv[1]);

    unique_ptr<tcp_server> user(new tcp_server(port)); // 自动析构

    // 登记消息对应的方法
    user->registr("ping", Ping);
    user->registr("translate", Translate);
    user->registr("transform", Transform);
    user->registr("default_func", default_func);

    user->inite();
    user->start();

    return 0;
}